#include "ofMain.h"      
#include "ruby.h"
#include "baseApp.h"

typedef VALUE RubyType(...); 

VALUE mod;

//---------------------------------------------------- ofAppRunner
VALUE wrap_ofSetupOpenGL(VALUE self, VALUE w, VALUE h, VALUE screenMode)   
{    
	ofSetupOpenGL(NUM2INT(w), NUM2INT(h), NUM2INT(screenMode));
	return Qnil;  
}

VALUE wrap_ofRunApp(VALUE self, VALUE OFSA)   
{    
	baseApp *app;
	Data_Get_Struct(OFSA, baseApp, app);
	ofRunApp(app);
	return Qnil;  
}

VALUE wrap_ofGetFrameRate(VALUE self)   
{    
	return rb_float_new(ofGetFrameRate());
}

VALUE wrap_ofSetFrameRate(VALUE self, VALUE targetRate)   
{    
	ofSetFrameRate(NUM2INT(targetRate));
	return Qnil;
}

VALUE wrap_ofSleepMillis(VALUE self, VALUE millis)   
{    
	ofSleepMillis(NUM2INT(millis));
	return Qnil;
}

VALUE wrap_ofHideCursor(VALUE self)   
{    
	ofHideCursor();
	return Qnil;
}

VALUE wrap_ofShowCursor(VALUE self)   
{    
	ofShowCursor();
	return Qnil;
}

VALUE wrap_ofGetWindowPositionX(VALUE self)   
{     
	return INT2FIX(ofGetWindowPositionX());  
} 

VALUE wrap_ofGetWindowPositionY(VALUE self)   
{     
	return INT2FIX(ofGetWindowPositionY());  
}

VALUE wrap_ofGetScreenWidth(VALUE self)   
{     
	return INT2FIX(ofGetScreenWidth());  
} 

VALUE wrap_ofGetScreenHeight(VALUE self)   
{     
	return INT2FIX(ofGetScreenHeight());
}

VALUE wrap_ofGetWindowMode(VALUE self)   
{     
	return INT2FIX(ofGetWindowMode());  
} 

VALUE wrap_ofGetWidth(VALUE self)   
{     
	return INT2FIX(ofGetWidth());
}

VALUE wrap_ofGetHeight(VALUE self)   
{     
	return INT2FIX(ofGetHeight());
}

VALUE wrap_ofSetWindowPosition(VALUE self, VALUE x, VALUE y)
{
	ofSetWindowPosition(NUM2INT(x), NUM2INT(y));
	return Qnil;
}

VALUE wrap_ofSetWindowShape(VALUE self, VALUE width, VALUE height)
{
	ofSetWindowShape(NUM2INT(width), NUM2INT(height));
	return Qnil;
}

VALUE wrap_ofSetWindowTitle(VALUE self, VALUE title)
{
	ofSetWindowTitle(StringValuePtr(title));
	return Qnil;
}

VALUE wrap_ofSetFullscreen(VALUE self, VALUE fullscreen)
{
	ofSetFullscreen(RTEST(fullscreen));
	return Qnil;
}

VALUE wrap_ofToggleFullscreen(VALUE self)
{
	ofToggleFullscreen();
	return Qnil;
}

VALUE wrap_ofSetVerticalSync(VALUE self, VALUE bSync)
{
	ofSetVerticalSync(RTEST(bSync));
	return Qnil;
}

//---------------------------------------------------- ofSimpleApp
void ofSimpleApp_mark(baseApp *app)
{
	rb_gc_mark(app->obj);
}

void ofSimpleApp_free(baseApp *app)
{
	delete app;
}

VALUE ofSimpleApp_alloc(VALUE klass)   
{    
	baseApp *app;
    VALUE obj;

    app = new baseApp();
    obj = Data_Wrap_Struct(klass, ofSimpleApp_mark, ofSimpleApp_free, app);
    app->obj = obj;
    return obj;
}

void setup();
void update();
void draw();
void exit();
		
void keyPressed(int key);
void keyReleased(int key);
		
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased();
		
void audioReceived(float *input, int bufferSize, int nChannels);
void audioRequested(float *output, int bufferSize, int nChannels);

VALUE wrap_ofSimpleApp_setup()   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_update()   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_draw()   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_exit()   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_keyPressed(VALUE key)   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_keyReleased(VALUE key)   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_mouseMoved(VALUE x, VALUE y )   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_mouseDragged(VALUE x, VALUE y, VALUE button)   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_mousePressed(VALUE x, VALUE y, VALUE button)   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_mouseReleased()   
{    
	return Qnil;  
}	

VALUE wrap_ofSimpleApp_audioReceived(VALUE input, VALUE bufferSize, VALUE nChannels)   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_audioRequested(VALUE output, VALUE bufferSize, VALUE nChannels)   
{    
	return Qnil;  
}

VALUE wrap_ofSimpleApp_mouseX(VALUE self)   
{    
	baseApp *app;
	Data_Get_Struct(self, baseApp, app);
	return INT2FIX(app->mouseX);
}

VALUE wrap_ofSimpleApp_mouseY(VALUE self)   
{    
	baseApp *app;
	Data_Get_Struct(self, baseApp, app);
	return INT2FIX(app->mouseY);
}

//---------------------------------------------------- ofUtils
VALUE wrap_ofGetElapsedTimef(VALUE self)   
{    
	return rb_float_new(ofGetElapsedTimef());  
}

VALUE wrap_ofGetElapsedTimeMillis(VALUE self)   
{    
	return INT2NUM(ofGetElapsedTimeMillis());  
}

VALUE wrap_ofGetFrameNum(VALUE self)   
{    
	return INT2NUM(ofGetFrameNum());  
}

VALUE wrap_ofGetSeconds(VALUE self)   
{    
	return INT2NUM(ofGetSeconds());  
}

VALUE wrap_ofGetMinutes(VALUE self)   
{    
	return INT2NUM(ofGetMinutes());  
}

VALUE wrap_ofGetHours(VALUE self)   
{    
	return INT2NUM(ofGetHours());  
}

VALUE wrap_ofGetYear(VALUE self)   
{    
	return INT2NUM(ofGetYear());  
}

VALUE wrap_ofGetMonth(VALUE self)   
{    
	return INT2NUM(ofGetMonth());  
}

VALUE wrap_ofGetDay(VALUE self)   
{    
	return INT2NUM(ofGetDay());  
}

int ofGetWeekday(); //<----------------- stopgap
VALUE wrap_ofGetWeekDay(VALUE self)   
{    
	return INT2NUM(ofGetWeekday());  
}

VALUE wrap_ofLaunchBrowser(VALUE self, VALUE url)
{
	ofLaunchBrowser(StringValuePtr(url));
	return Qnil;
}

VALUE wrap_ofToDataPath(VALUE self, VALUE path)
{
	return rb_str_new2(ofToDataPath(StringValuePtr(path)).c_str());
}

VALUE wrap_ofToString(int argc, VALUE *argv, VALUE self)   
{    
	VALUE value;
	VALUE precision;
	string result;
	
	if (rb_scan_args(argc, argv, "11", &value, &precision) == 1) {
		if (TYPE(value) == T_FLOAT) {
			result = ofToString(NUM2DBL(value));
		}
		else {
			result = ofToString(NUM2INT(value));
		}
	}
	else {
		result = ofToString(NUM2DBL(value), NUM2INT(precision));
	}
	
	return rb_str_new2(result.c_str());  
}

VALUE wrap_ofGetVersionInfo(VALUE self)
{
	return rb_str_new2(ofGetVersionInfo().c_str());
}

//---------------------------------------------------- ofGraphics helper
static int id_bgColor = rb_intern("__bgColor__");
static int id_aset = rb_intern("[]=");

VALUE bgColorProxy_aset(int argc, VALUE *argv, VALUE self)
{
	VALUE result;
	int index;

	if (argc != 2) {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc);
	}
	
	index = NUM2INT(argv[0]);
	if (index < 0 || 3 < index) {
		rb_raise(rb_eIndexError, "index %ld out of array", index);
	}
	
	ofBgColorPtr()[index] = NUM2DBL(argv[1]);
	
	return rb_call_super(argc, argv);
}

//---------------------------------------------------- ofGraphics
VALUE wrap_ofBackground(VALUE self, VALUE r, VALUE g, VALUE b)
{
	VALUE col;
	int ir;
	int ig;
	int ib;
	
	ir = NUM2INT(r);
	ig = NUM2INT(g);
	ib = NUM2INT(b);
	
	col = rb_cvar_get(mod, id_bgColor);
	rb_funcall(col, id_aset, 2, INT2FIX(0), rb_float_new(ir / (float)255.0f));
	rb_funcall(col, id_aset, 2, INT2FIX(1), rb_float_new(ig / (float)255.0f));
	rb_funcall(col, id_aset, 2, INT2FIX(2), rb_float_new(ib / (float)255.0f));
	
	ofBackground(ir, ig, ib);
	
	return Qnil;
}

VALUE wrap_ofBgColorPtr(VALUE self)
{
	return rb_cvar_get(mod, id_bgColor);
}

VALUE wrap_ofSetBackgroundAuto(VALUE self, VALUE bManual)
{
	ofSetBackgroundAuto(RTEST(bManual));
	return Qnil;
}

VALUE wrap_ofSetRectMode(VALUE self, VALUE mode)
{
	ofSetRectMode(NUM2INT(mode));
	return Qnil;
}

VALUE wrap_ofbClearBg(VALUE self)
{
	return ofbClearBg() ? Qtrue : Qfalse;
}

VALUE wrap_ofGetRectMode(VALUE self)
{
	return INT2FIX(ofGetRectMode());
}

VALUE wrap_ofTriangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
{
	ofTriangle(NUM2DBL(x1), NUM2DBL(y1), NUM2DBL(x2), NUM2DBL(y2), NUM2DBL(x3), NUM2DBL(y3));
	return Qnil;
}

VALUE wrap_ofCircle(VALUE self, VALUE x, VALUE y, VALUE radius)
{
	ofCircle(NUM2DBL(x), NUM2DBL(y), NUM2DBL(radius));
	return Qnil;
}

VALUE wrap_ofEllipse(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
{
	ofEllipse(NUM2DBL(x), NUM2DBL(y), NUM2DBL(w), NUM2DBL(h));
	return Qnil;
}

VALUE wrap_ofLine(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
{
	ofLine(NUM2DBL(x1), NUM2DBL(y1), NUM2DBL(x2), NUM2DBL(y2));
	return Qnil;
}

VALUE wrap_ofRect(VALUE self, VALUE x1, VALUE y1, VALUE w, VALUE h)
{
	ofRect(NUM2DBL(x1), NUM2DBL(y1), NUM2DBL(w), NUM2DBL(h));
	return Qnil;
}

VALUE wrap_ofSetCircleResolution(VALUE self, VALUE res)
{
	ofSetCircleResolution(NUM2INT(res));
	return Qnil;
}

VALUE wrap_ofCurve(VALUE self, VALUE x0, VALUE y0, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
{
	ofCurve(NUM2DBL(x0), NUM2DBL(y0), NUM2DBL(x1), NUM2DBL(y1), NUM2DBL(x2), NUM2DBL(y2), NUM2DBL(x3), NUM2DBL(y3));
	return Qnil;
}

VALUE wrap_ofBezier(VALUE self, VALUE x0, VALUE y0, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
{
	ofBezier(NUM2DBL(x0), NUM2DBL(y0), NUM2DBL(x1), NUM2DBL(y1), NUM2DBL(x2), NUM2DBL(y2), NUM2DBL(x3), NUM2DBL(y3));
	return Qnil;
}

VALUE wrap_ofNoFill(VALUE self)
{
	ofNoFill();
	return Qnil;
}

VALUE wrap_ofFill(VALUE self)
{
	ofFill();
	return Qnil;
}

VALUE wrap_ofSetColor(int argc, VALUE *argv, VALUE self)   
{    
	if (argc == 1) {
		ofSetColor(NUM2INT(argv[0]));
	}
	else if (argc == 3) {
		ofSetColor(NUM2INT(argv[0]), NUM2INT(argv[1]), NUM2INT(argv[2]));
	}
	else if (argc == 4) {
		ofSetColor(NUM2INT(argv[0]), NUM2INT(argv[1]), NUM2INT(argv[2]), NUM2INT(argv[3]));
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 3 or 4)", argc);
	}
	return Qnil;  
}

VALUE wrap_ofEnableAlphaBlending(VALUE self)
{
	ofEnableAlphaBlending();
	return Qnil;
}

VALUE wrap_ofDisableAlphaBlending(VALUE self)
{
	ofDisableAlphaBlending();
	return Qnil;
}

VALUE wrap_ofEnableSmoothing(VALUE self)
{
	ofEnableSmoothing();
	return Qnil;
}

VALUE wrap_ofDisableSmoothing(VALUE self)
{
	ofDisableSmoothing();
	return Qnil;
}

VALUE wrap_ofDrawBitmapString(VALUE self, VALUE textString, VALUE x, VALUE y)
{
	ofDrawBitmapString(StringValuePtr(textString), NUM2DBL(x), NUM2DBL(y));
	return Qnil;
}

VALUE wrap_ofSetupScreen(VALUE self)
{
	ofSetupScreen();
	return Qnil;
}

VALUE wrap_ofCurveVertex(VALUE self, VALUE x, VALUE y)
{
	ofCurveVertex(NUM2DBL(x), NUM2DBL(y));
	return Qnil;
}

VALUE wrap_ofBezierVertex(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
{
	ofBezierVertex(NUM2DBL(x1), NUM2DBL(y1), NUM2DBL(x2), NUM2DBL(y2), NUM2DBL(x3), NUM2DBL(y3));
	return Qnil;
}

VALUE wrap_ofSetPolyMode(VALUE self, VALUE mode)
{
	ofSetPolyMode(NUM2INT(mode));
	return Qnil;
}

VALUE wrap_ofBeginShape(VALUE self)
{
	ofBeginShape();
	return Qnil;
}

VALUE wrap_ofVertex(VALUE self, VALUE x, VALUE y)
{
	ofVertex(NUM2DBL(x), NUM2DBL(y));
	return Qnil;
}

VALUE wrap_ofEndShape(int argc, VALUE *argv, VALUE self)   
{    
	VALUE bClose;
	if (rb_scan_args(argc, argv, "01", &bClose) == 0) {
		ofEndShape();
	}
	else {
		ofEndShape(RTEST(bClose));
	}
	return Qnil;  
}

VALUE wrap_ofNextContour(int argc, VALUE *argv, VALUE self)   
{    
	VALUE bClose;
	if (rb_scan_args(argc, argv, "01", &bClose) == 0) {
		ofNextContour();
	}
	else {
		ofNextContour(RTEST(bClose));
	}
	return Qnil;  
}

//---------------------------------------------------- ofImage
static VALUE eUninitializedError;

void ofImage_free(ofImage *img)
{
	delete img;
}

VALUE ofImage_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofImage_free, new ofImage());
}

VALUE ofImage_init_copy(VALUE copy, VALUE orig) {
	ofImage *orig_img;
	ofImage *copy_img;

	if (copy == orig) return copy;
	
	if (TYPE(orig) != T_DATA ||
		RDATA(orig)->dfree != (RUBY_DATA_FUNC)ofImage_free) {
	
		rb_raise(rb_eTypeError, "wrong argument type");
	}
	
	Data_Get_Struct(orig, ofImage, orig_img);
	Data_Get_Struct(copy, ofImage, copy_img);
	copy_img->clone(*orig_img);
	
	return copy;
}

//ファイルが見つからないケースと、形式が不明なケースでエラー投げるべきか？
VALUE wrap_ofImage_loadImage(VALUE self, VALUE fileName)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->loadImage(StringValuePtr(fileName));
	
	
	return Qnil;
}

//存在しないパスだと暗黙でセーブされないのはいいのか？
VALUE wrap_ofImage_saveImage(VALUE self, VALUE fileName)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->saveImage(StringValuePtr(fileName));
	
	return Qnil;
}

VALUE wrap_ofImage_allocate(VALUE self, VALUE w, VALUE h, VALUE type)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->allocate(NUM2INT(w), NUM2INT(h), NUM2INT(type));
	
	return Qnil;
}

VALUE wrap_ofImage_clear(VALUE self)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->clear();
	
	return Qnil;
}

//自前で画像を生成する場合、allocate後、setFromPixelsしないといけないのはいかがなものか？
VALUE wrap_ofImage_getPixels(VALUE self)
{
	ofImage *img;
	VALUE result;
	long len;
	long i;
	unsigned char *pixels;
	
	Data_Get_Struct(self, ofImage, img);
	pixels = img->getPixels();
	
	if (pixels == NULL) {
		rb_raise(eUninitializedError, "ofImage has not been allocated yet");
	}
	
	len = img->width * img->height * img->bpp / 8;
	
	VALUE *values = ALLOC_N(VALUE, len);
	for (i = 0; i < len; i++) {
        values[i] = CHR2FIX(pixels[i]); 
    } 
	result = rb_ary_new4(len, values); 
	free(values);
	
	return result;
}

VALUE wrap_ofImage_setFromPixels(int argc, VALUE *argv, VALUE self) 
{
	VALUE pixels;
	VALUE w;
	VALUE h;
	VALUE newType;
	VALUE bOrderIsRGB;
	
	unsigned char *cPixels;
	int cW;
	int cH;
	int cNewType;
	bool cbOrderIsRGB;
	
	long len;
	long i;
	VALUE *ptr;
	ofImage *img;
	
	rb_scan_args(argc, argv, "41", &pixels, &w, &h, &newType, &bOrderIsRGB);
	if (NIL_P(pixels)) {
		rb_raise(rb_eArgError, "the array is nil");
	}
	pixels = rb_Array(pixels);
	cW = NUM2INT(w);
	cH = NUM2INT(h);
	cNewType = NUM2INT(newType);
	cbOrderIsRGB = RTEST(bOrderIsRGB);
	
	len = RARRAY(pixels)->len;
	ptr = RARRAY(pixels)->ptr;
	cPixels = new unsigned char[len]; 
	for (i = 0; i < len; i++) {
        cPixels[i] = (unsigned char)NUM2INT(ptr[i]); 
    } 
	
	Data_Get_Struct(self, ofImage, img);
	if (argc == 4) {
		img->setFromPixels(cPixels, cW, cH, cNewType);
	}
	else {
		img->setFromPixels(cPixels, cW, cH, cNewType, cbOrderIsRGB);
	}
	
	delete[] cPixels;
	
	return Qnil;
}

VALUE wrap_ofImage_setImageType(VALUE self, VALUE type)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->setImageType(NUM2INT(type));
	
	return Qnil;
}

VALUE wrap_ofImage_resize(VALUE self, VALUE newWidth, VALUE newHeight)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->resize(NUM2INT(newWidth), NUM2INT(newHeight));
	
	return Qnil;
}

VALUE wrap_ofImage_grabScreen(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->grabScreen(NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
	
	return Qnil;
}

VALUE wrap_ofImage_type(VALUE self)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	return INT2FIX(img->type);
}

VALUE wrap_ofImage_width(VALUE self)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	return INT2FIX(img->width);
}

VALUE wrap_ofImage_height(VALUE self)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	return INT2FIX(img->height);
}

VALUE wrap_ofImage_bpp(VALUE self)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	return INT2FIX(img->bpp);
}

VALUE wrap_ofImage_setUseTexture(VALUE self, VALUE bUse)
{
	ofImage *img;
	Data_Get_Struct(self, ofImage, img);
	
	img->setUseTexture(RTEST(bUse));
	
	return Qnil;
}

VALUE wrap_ofImage_draw(int argc, VALUE *argv, VALUE self)   
{    
	ofImage *img;
	VALUE x;
	VALUE y;
	VALUE w;
	VALUE h;
	
	rb_scan_args(argc, argv, "22", &x, &y, &w, &h);
	Data_Get_Struct(self, ofImage, img);
	
	if (argc == 2) {
		img->draw(NUM2INT(x), NUM2INT(y));
	}
	else if (argc == 4) {
		img->draw(NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 4)", argc);
	}
	
	return Qnil;  
}

//---------------------------------------------------- ofTexture
void ofTexture_free(ofTexture *tex)
{
	delete tex;
}

VALUE ofTexture_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofTexture_free, new ofTexture());
}

VALUE wrap_ofTexture_allocate(VALUE self, VALUE w, VALUE h, VALUE internalGlDataType)
{
	ofTexture *tex;
	Data_Get_Struct(self, ofTexture, tex);
	
	tex->allocate(NUM2INT(w), NUM2INT(h), NUM2INT(internalGlDataType));
	
	return Qnil;
}

VALUE wrap_ofTexture_clear(VALUE self)
{
	ofTexture *tex;
	Data_Get_Struct(self, ofTexture, tex);
	
	tex->clear();
	
	return Qnil;
}

VALUE wrap_ofTexture_loadData(VALUE self, VALUE data, VALUE w, VALUE h, VALUE glDataType) 
{
	unsigned char *cPixels;
	int cW;
	int cH;
	int cGLDataType;

	long len;
	long i;
	VALUE *ptr;
	ofTexture *tex;
	
	cW = NUM2INT(w);
	cH = NUM2INT(h);
	cGLDataType = NUM2INT(glDataType);
	
	if (NIL_P(data)) {
		rb_raise(rb_eArgError, "the array is nil");
	}
	data = rb_Array(data);
	len = RARRAY(data)->len;
	ptr = RARRAY(data)->ptr;
	cPixels = new unsigned char[len]; 
	for (i = 0; i < len; i++) {
        cPixels[i] = (unsigned char)NUM2CHR(ptr[i]); 
    } 
	
	Data_Get_Struct(self, ofTexture, tex);
	tex->loadData(cPixels, cW, cH, cGLDataType);
	
	delete[] cPixels;
	
	return Qnil;
}

VALUE wrap_ofTexture_loadScreenData(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
{
	ofTexture *tex;
	Data_Get_Struct(self, ofTexture, tex);
	
	tex->loadScreenData(NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
	
	return Qnil;
}

VALUE wrap_ofTexture_draw(int argc, VALUE *argv, VALUE self)   
{    
	ofTexture *tex;
	VALUE x;
	VALUE y;
	VALUE w;
	VALUE h;
	
	rb_scan_args(argc, argv, "22", &x, &y, &w, &h);
	Data_Get_Struct(self, ofTexture, tex);
	
	if (argc == 2) {
		tex->draw(NUM2INT(x), NUM2INT(y));
	}
	else if (argc == 4) {
		tex->draw(NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 4)", argc);
	}
	
	return Qnil;  
}

//---------------------------------------------------- ofRectangle
static VALUE rb_cRectangle;

void ofRectangle_free(ofRectangle *rect)
{
	delete rect;
}

VALUE ofRectangle_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofRectangle_free, new ofRectangle());
}

VALUE ofRectangle_init_copy(VALUE copy, VALUE orig) {
	ofRectangle *orig_rect;
	ofRectangle *copy_rect;

	if (copy == orig) return copy;
	
	if (TYPE(orig) != T_DATA ||
		RDATA(orig)->dfree != (RUBY_DATA_FUNC)ofRectangle_free) {
	
		rb_raise(rb_eTypeError, "wrong argument type");
	}
	
	Data_Get_Struct(orig, ofRectangle, orig_rect);
	Data_Get_Struct(copy, ofRectangle, copy_rect);
	copy_rect->x = orig_rect->x;
	copy_rect->y = orig_rect->y;
	copy_rect->width = orig_rect->width;
	copy_rect->height = orig_rect->height;
	
	return copy;
}

VALUE wrap_ofRectangle_initialize(int argc, VALUE *argv, VALUE self)  
{ 
	ofRectangle *rect;
	VALUE x;
	VALUE y;
	VALUE w;
	VALUE h;
	float cx = 0;
	float cy = 0;
	float cw = 0;
	float ch = 0;
	
	rb_scan_args(argc, argv, "04", &x, &y, &w, &h);
	Data_Get_Struct(self, ofRectangle, rect);
	
	if (argc >= 1) {
		cx = NUM2DBL(x);
	}
	if (argc >= 2) {
		cy = NUM2DBL(y);
	}
	if (argc >= 3) {
		cw = NUM2DBL(w);
	}
	if (argc >= 4) {
		ch = NUM2DBL(h);
	}
	
	rect->x = cx;
	rect->y = cy;
	rect->width = cw;
	rect->height = ch;
	
    return self;
}

VALUE wrap_ofRectangle_x(VALUE self)
{
	ofRectangle *rect;
	Data_Get_Struct(self, ofRectangle, rect);
	return rb_float_new(rect->x);
}

VALUE wrap_ofRectangle_y(VALUE self)
{
	ofRectangle *rect;
	Data_Get_Struct(self, ofRectangle, rect);
	return rb_float_new(rect->y);
}

VALUE wrap_ofRectangle_width(VALUE self)
{
	ofRectangle *rect;
	Data_Get_Struct(self, ofRectangle, rect);
	return rb_float_new(rect->width);
}

VALUE wrap_ofRectangle_height(VALUE self)
{
	ofRectangle *rect;
	Data_Get_Struct(self, ofRectangle, rect);
	return rb_float_new(rect->height);
}

//---------------------------------------------------- ofTrueTypeFont
void ofTrueTypeFont_free(ofTrueTypeFont *font)
{
	delete font;
}

VALUE ofTrueTypeFont_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofTrueTypeFont_free, new ofTrueTypeFont());
}

VALUE wrap_ofTrueTypeFont_loadFont(int argc, VALUE *argv, VALUE self)   
{    
	ofTrueTypeFont *font;
	VALUE filename;
	VALUE fontsize;
	VALUE bAntiAliased;
	VALUE bFullCharacterSet;
	
	rb_scan_args(argc, argv, "22", &filename, &fontsize, &bAntiAliased, &bFullCharacterSet);
	Data_Get_Struct(self, ofTrueTypeFont, font);
	
	if (argc == 2) {
		font->loadFont(StringValuePtr(filename), NUM2INT(fontsize));
	}
	else if (argc == 4) {
		font->loadFont(StringValuePtr(filename), NUM2INT(fontsize), RTEST(bAntiAliased), RTEST(bFullCharacterSet));
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 4)", argc);
	}
	
	return Qnil;  
}

VALUE wrap_ofTrueTypeFont_bLoadedOk(VALUE self)
{
	ofTrueTypeFont *font;
	Data_Get_Struct(self, ofTrueTypeFont, font);
	return font->bLoadedOk ? Qtrue : Qfalse;
}

VALUE wrap_ofTrueTypeFont_bAntiAlised(VALUE self)
{
	ofTrueTypeFont *font;
	Data_Get_Struct(self, ofTrueTypeFont, font);
	return font->bAntiAlised ? Qtrue : Qfalse;
}

VALUE wrap_ofTrueTypeFont_bFullCharacterSet(VALUE self)
{
	ofTrueTypeFont *font;
	Data_Get_Struct(self, ofTrueTypeFont, font);
	return font->bFullCharacterSet ? Qtrue : Qfalse;
}

VALUE wrap_ofTrueTypeFont_getLineHeight(VALUE self)
{
	ofTrueTypeFont *font;
	Data_Get_Struct(self, ofTrueTypeFont, font);
	return rb_float_new(font->getLineHeight());
}

VALUE wrap_ofTrueTypeFont_setLineHeight(VALUE self, VALUE height)
{
	ofTrueTypeFont *font;
	Data_Get_Struct(self, ofTrueTypeFont, font);
	
	font->setLineHeight(NUM2DBL(height));
	
	return Qnil;
}

ofTrueTypeFont *get_font(VALUE obj)
{
	ofTrueTypeFont *font;
	
	Data_Get_Struct(obj, ofTrueTypeFont, font);
	if (!font->bLoadedOk) {
		rb_raise(eUninitializedError, "ofTrueTypeFont has not been allocated yet");
	}
	return font;
}

VALUE wrap_ofTrueTypeFont_stringWidth(VALUE self, VALUE s)
{
	ofTrueTypeFont *font;
	
	font = get_font(self);
	return rb_float_new(font->stringWidth(StringValuePtr(s)));
}

VALUE wrap_ofTrueTypeFont_stringHeight(VALUE self, VALUE s)
{
	ofTrueTypeFont *font;
	
	font = get_font(self);
	return rb_float_new(font->stringHeight(StringValuePtr(s)));
}

VALUE wrap_ofTrueTypeFont_getStringBoundingBox(VALUE self, VALUE s, VALUE x, VALUE y)
{
	ofTrueTypeFont *font;
	ofRectangle rect;
	VALUE oRectangleInitArgs[4];
	
	font = get_font(self);
	rect = font->getStringBoundingBox(StringValuePtr(s), NUM2DBL(x), NUM2DBL(y));
	
	oRectangleInitArgs[0] = rb_float_new(rect.x);
	oRectangleInitArgs[1] = rb_float_new(rect.y);
	oRectangleInitArgs[2] = rb_float_new(rect.width);
	oRectangleInitArgs[3] = rb_float_new(rect.height);
	
	return rb_class_new_instance(4, oRectangleInitArgs, rb_cRectangle);
}

VALUE wrap_ofTrueTypeFont_drawString(VALUE self, VALUE s, VALUE x, VALUE y)
{
	ofTrueTypeFont *font;
	
	font = get_font(self);
	font->drawString(StringValuePtr(s), NUM2DBL(x), NUM2DBL(y));
	
	return Qnil;
}

VALUE wrap_ofTrueTypeFont_nCharacters(VALUE self)
{
	ofTrueTypeFont *font;
	Data_Get_Struct(self, ofTrueTypeFont, font);
	return INT2NUM(font->nCharacters);
}

//---------------------------------------------------- ofSoundStream
VALUE wrap_ofSoundStreamSetup(int argc, VALUE *argv, VALUE self) 
{    
	VALUE nOutputChannels;
	VALUE nInputChannels;
	VALUE ofsa;
	VALUE sampleRate;
	VALUE bufferSize;
	VALUE nBuffers;
	ofSimpleApp *app;

	rb_scan_args(argc, argv, "33", &nOutputChannels, &nInputChannels, &ofsa, &sampleRate, &bufferSize, &nBuffers);
	Data_Get_Struct(ofsa, ofSimpleApp, app);
	
	if (argc == 3) {
		ofSoundStreamSetup(NUM2INT(nOutputChannels), NUM2INT(nInputChannels), app);
	}
	else if (argc == 6) {
		ofSoundStreamSetup(NUM2INT(nOutputChannels), NUM2INT(nInputChannels), app, NUM2INT(sampleRate), NUM2INT(bufferSize), NUM2INT(nBuffers));
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 3 or 6)", argc);
	}
	
	return Qnil;  
}

VALUE wrap_ofSoundStreamStop(VALUE self) 
{    
	ofSoundStreamStop();
	return Qnil;  
}

VALUE wrap_ofSoundStreamStart(VALUE self) 
{    
	ofSoundStreamStart();
	return Qnil;  
}

VALUE wrap_ofSoundStreamClose(VALUE self) 
{    
	ofSoundStreamClose();
	return Qnil;  
}

VALUE wrap_ofSoundStreamListDevices(VALUE self) 
{    
	ofSoundStreamListDevices();
	return Qnil;  
}

//---------------------------------------------------- ofSoundPlayer
VALUE wrap_ofSoundStopAll(VALUE self) 
{    
	ofSoundStopAll();
	return Qnil;  
}

VALUE wrap_ofSoundSetVolume(VALUE self, VALUE vol) 
{    
	ofSoundSetVolume(NUM2DBL(vol));
	return Qnil;  
}

VALUE wrap_ofSoundGetSpectrum(VALUE self, VALUE nBands) 
{    
	VALUE result;
	int len;
	int i;
	float *spec;
	
	len = NUM2INT(nBands);
	spec = ofSoundGetSpectrum(len);
	
	result = rb_ary_new2(len);
	for (i = 0; i < len; i++) {
		rb_ary_store(result, i, rb_float_new(spec[i]));
	} 
	
	return result; 
}

void ofSoundPlayer_free(ofSoundPlayer *snd)
{
	delete snd;
}

VALUE ofSoundPlayer_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofSoundPlayer_free, new ofSoundPlayer());
}

VALUE wrap_ofSoundPlayer_loadSound(int argc, VALUE *argv, VALUE self)   
{    
	ofSoundPlayer *snd;
	VALUE filename;
	VALUE stream;
	
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	if (rb_scan_args(argc, argv, "11", &filename, &stream) == 1) {
		snd->loadSound(StringValuePtr(filename));
	}
	else {
		snd->loadSound(StringValuePtr(filename), RTEST(stream));
	}
	
	return Qnil;  
}

//unload後にplay呼ぶとBus Errorが起きるけど、GC以外のunloadは禁じ手とすべきか？
//それとも、ofSoundPlayerの派生クラスにフラグ持たせて例外投げるようにするか？
VALUE wrap_ofSoundPlayer_unloadSound(VALUE self)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->unloadSound();
	
	return Qnil;  
}

//再生中もGCされれば音が消えるのは仕様ってことにしちゃう？
//効果音ならすときにローカル変数使えないのはひどいよなぁ
VALUE wrap_ofSoundPlayer_play(VALUE self)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->play();
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_stop(VALUE self)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->stop();
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_setVolume(VALUE self, VALUE vol)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->setVolume(NUM2DBL(vol));
	
	return Qnil;  
} 

VALUE wrap_ofSoundPlayer_setPan(VALUE self, VALUE pan)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->setPan(NUM2DBL(pan));
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_setSpeed(VALUE self, VALUE spd)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->setSpeed(NUM2DBL(spd));
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_setPaused(VALUE self, VALUE bP)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->setPaused(RTEST(bP));
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_setLoop(VALUE self, VALUE bLP)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->setLoop(RTEST(bLP));
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_setMultiPlay(VALUE self, VALUE bMp)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->setMultiPlay(RTEST(bMp));
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_setPosition(VALUE self, VALUE pct)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	
	snd->setPosition(NUM2DBL(pct));
	
	return Qnil;  
}

VALUE wrap_ofSoundPlayer_getPosition(VALUE self)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	return rb_float_new(snd->getPosition());
}

VALUE wrap_ofSoundPlayer_getIsPlaying(VALUE self)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	return snd->getIsPlaying() ? Qtrue : Qfalse;
}

VALUE wrap_ofSoundPlayer_getSpeed(VALUE self)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	return rb_float_new(snd->getSpeed());
}

VALUE wrap_ofSoundPlayer_getPan(VALUE self)   
{    
	ofSoundPlayer *snd;
	Data_Get_Struct(self, ofSoundPlayer, snd);
	return rb_float_new(snd->getPan());
}

//---------------------------------------------------- ofVideoPlayer
void ofVideoPlayer_free(ofVideoPlayer *mov)
{
	delete mov;
}

VALUE ofVideoPlayer_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofVideoPlayer_free, new ofVideoPlayer());
}

VALUE wrap_ofVideoPlayer_loadMovie(VALUE self, VALUE name)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	if (!mov->loadMovie(StringValuePtr(name))) {
		rb_raise(rb_eStandardError, "cannot load movie");
	}
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_closeMovie(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->closeMovie();
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_idleMovie(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->idleMovie();
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_play(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->play();
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_stop(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->stop();
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_width(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return INT2FIX(mov->width);
}

VALUE wrap_ofVideoPlayer_height(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return INT2FIX(mov->height);
}

VALUE wrap_ofVideoPlayer_speed(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return rb_float_new(mov->speed);
}

VALUE wrap_ofVideoPlayer_bLoaded(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return mov->bLoaded ? Qtrue : Qfalse;
}

VALUE wrap_ofVideoPlayer_isFrameNew(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return mov->isFrameNew() ? Qtrue : Qfalse;
}

VALUE wrap_ofVideoPlayer_getPixels(VALUE self)
{
	ofVideoPlayer *mov;
	VALUE result;
	long len;
	long i;
	unsigned char *pixels;
	
	Data_Get_Struct(self, ofVideoPlayer, mov);
	pixels = mov->getPixels();
	
	if (pixels == NULL) {
		rb_raise(eUninitializedError, "pixels has not been initialized yet");
	}
	
	len = mov->width * mov->height * 3;
	
	VALUE *values = ALLOC_N(VALUE, len);
	for (i = 0; i < len; i++) {
        values[i] = CHR2FIX(pixels[i]); 
    } 
	result = rb_ary_new4(len, values); 
	free(values);
	
	return result;
}

VALUE wrap_ofVideoPlayer_getPosition(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return rb_float_new(mov->getPosition());
}

VALUE wrap_ofVideoPlayer_getSpeed(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return rb_float_new(mov->getSpeed());
}

VALUE wrap_ofVideoPlayer_getDuration(VALUE self)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	return rb_float_new(mov->getDuration());
}

VALUE wrap_ofVideoPlayer_setPosition(VALUE self, VALUE pct)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->setPosition(NUM2DBL(pct));
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_setVolume(VALUE self, VALUE volume)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->setVolume(NUM2DBL(volume));
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_setLoopState(VALUE self, VALUE state)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->setLoopState(NUM2INT(state));
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_setSpeed(VALUE self, VALUE speed)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->setSpeed(NUM2DBL(speed));
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_setUseTexture(VALUE self, VALUE bUse)
{
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->setUseTexture(RTEST(bUse));
	
	return Qnil;
}

VALUE wrap_ofVideoPlayer_draw(int argc, VALUE *argv, VALUE self)   
{    
	ofVideoPlayer *mov;
	VALUE x;
	VALUE y;
	VALUE w;
	VALUE h;
	
	rb_scan_args(argc, argv, "22", &x, &y, &w, &h);
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	if (argc == 2) {
		mov->draw(NUM2INT(x), NUM2INT(y));
	}
	else if (argc == 4) {
		mov->draw(NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 4)", argc);
	}
	
	return Qnil;  
}

VALUE wrap_ofVideoPlayer_setPaused(VALUE self, VALUE bPause)   
{    
	ofVideoPlayer *mov;
	Data_Get_Struct(self, ofVideoPlayer, mov);
	
	mov->setPaused(RTEST(bPause));
	
	return Qnil;  
}

//---------------------------------------------------- ofVideoGrabber
void ofVideoGrabber_free(ofVideoGrabber *cam)
{
	delete cam;
}

VALUE ofVideoGrabber_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofVideoGrabber_free, new ofVideoGrabber());
}

VALUE wrap_ofVideoGrabber_listDevices(VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->listDevices();
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_isFrameNew(VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	return cam->isFrameNew() ? Qtrue : Qfalse;
}

VALUE wrap_ofVideoGrabber_grabFrame(VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->grabFrame();
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_close(VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->close();
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_initGrabber(VALUE self, VALUE w, VALUE h)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->initGrabber(NUM2INT(w), NUM2INT(h));
	
	return Qnil;  
}

/*
VALUE wrap_ofVideoGrabber_initGrabber(int argc, VALUE *argv, VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	VALUE w;
	VALUE h;
	VALUE bTexture;
	
	if (rb_scan_args(argc, argv, "21", &w, &h, &bTexture) == 2) {
		cam->initGrabber(NUM2INT(w), NUM2INT(h));
	}
	else {
		cam->initGrabber(NUM2INT(w), NUM2INT(h), RTEST(bTexture));
	}
	
	return Qnil;  
}
*/

VALUE wrap_ofVideoGrabber_videoSettings(VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->videoSettings();
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_getPixels(VALUE self)
{
	ofVideoGrabber *cam;
	VALUE result;
	long len;
	long i;
	unsigned char *pixels;
	
	Data_Get_Struct(self, ofVideoGrabber, cam);
	pixels = cam->getPixels();
	
	if (pixels == NULL) {
		rb_raise(eUninitializedError, "pixels has not been initialized yet");
	}
	
	len = cam->width * cam->height * 3;
	
	VALUE *values = ALLOC_N(VALUE, len);
	for (i = 0; i < len; i++) {
        values[i] = CHR2FIX(pixels[i]); 
    } 
	result = rb_ary_new4(len, values); 
	free(values);
	
	return result;
}

VALUE wrap_ofVideoGrabber_setVerbose(VALUE self, VALUE bTalkToMe)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->setVerbose(RTEST(bTalkToMe));
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_setDeviceID(VALUE self, VALUE _deviceID)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->setVerbose(NUM2INT(_deviceID));
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_setUseTexture(VALUE self, VALUE bUse)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	cam->setUseTexture(RTEST(bUse));
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_draw(int argc, VALUE *argv, VALUE self)   
{    
	ofVideoGrabber *cam;
	VALUE x;
	VALUE y;
	VALUE w;
	VALUE h;
	
	rb_scan_args(argc, argv, "22", &x, &y, &w, &h);
	Data_Get_Struct(self, ofVideoGrabber, cam);
	
	if (argc == 2) {
		cam->draw(NUM2INT(x), NUM2INT(y));
	}
	else if (argc == 4) {
		cam->draw(NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 4)", argc);
	}
	
	return Qnil;  
}

VALUE wrap_ofVideoGrabber_width(VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	return INT2FIX(cam->width);
}

VALUE wrap_ofVideoGrabber_height(VALUE self)   
{    
	ofVideoGrabber *cam;
	Data_Get_Struct(self, ofVideoGrabber, cam);
	return INT2FIX(cam->height);
}

//---------------------------------------------------- ofSerial
void ofSerial_free(ofSerial *seri)
{
	delete seri;
}

VALUE ofSerial_alloc(VALUE klass)   
{    
    return Data_Wrap_Struct(klass, 0, ofSerial_free, new ofSerial());
}

VALUE wrap_ofSerial_enumerateDevices(VALUE self)   
{    
	ofSerial *seri;
	Data_Get_Struct(self, ofSerial, seri);
	
	seri->enumerateDevices();
	
	return Qnil;  
}

VALUE wrap_ofSerial_close(VALUE self)   
{    
	ofSerial *seri;
	Data_Get_Struct(self, ofSerial, seri);
	
	seri->close();
	
	return Qnil;  
}

VALUE setup_str_int(VALUE *args)
{
	ofSerial *seri;
	VALUE self = args[0];
	string portName = StringValuePtr(args[1]);
	int baudrate = NUM2INT(args[2]);
	
	Data_Get_Struct(self, ofSerial, seri);
	return seri->setup(portName, baudrate) ? Qtrue : Qfalse;
}

VALUE setup_int_int(VALUE *args)
{
	ofSerial *seri;
	VALUE self = args[0];
	int deviceNumber = NUM2INT(args[1]);
	int baudrate = NUM2INT(args[2]);
	
	Data_Get_Struct(self, ofSerial, seri);
	return seri->setup(deviceNumber, baudrate) ? Qtrue : Qfalse;
}

VALUE wrap_ofSerial_setup(int argc, VALUE *argv, VALUE self)   
{    
	ofSerial *seri;
	VALUE arg1;
	VALUE arg2;
	VALUE args[3];
	VALUE result;
	bool setupped;
	
	rb_scan_args(argc, argv, "02", &arg1, &arg2);
	Data_Get_Struct(self, ofSerial, seri);
	
	if (argc == 0) {
		result = seri->setup() ? Qtrue : Qfalse;
	}
	else if (argc == 2) {
		NUM2INT(arg2);
		args[0] = self;
		args[1] = arg1;
		args[2] = arg2;
		result = rb_rescue((RubyType *)setup_str_int, (VALUE)args, (RubyType *)setup_int_int, (VALUE)args);
	}
	else {
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 2)", argc);
	}
	
	return result;  
}

VALUE wrap_ofSerial_readBytes(VALUE self, VALUE buffer, VALUE length)   
{    
	ofSerial *seri;
	unsigned char *bytes;
	int len;
	int i;
	int nBytesRead;
	
	Check_Type(buffer, T_ARRAY);
	len = NUM2INT(length);
	
	Data_Get_Struct(self, ofSerial, seri);
	bytes = new unsigned char[len]; 
	nBytesRead = seri->readBytes(bytes, len);
	
	for (i = 0; i < nBytesRead; i++) {
		rb_ary_store(buffer, i, INT2FIX(bytes[i]));
	}
	delete[] bytes;
	
	return INT2NUM(nBytesRead);
}

VALUE wrap_ofSerial_writeBytes(VALUE self, VALUE buffer, VALUE length)   
{    
	ofSerial *seri;
	unsigned char *bytes;
	int ary_len;
	int len;
	int i;
	int nBytesWrite;
	VALUE *ptr;
	
	Data_Get_Struct(self, ofSerial, seri);
	
	if (NIL_P(buffer)) {
		rb_raise(rb_eArgError, "the array is nil");
	}
	buffer = rb_Array(buffer);
	ary_len = RARRAY(buffer)->len;
	ptr = RARRAY(buffer)->ptr;
	
	len = NUM2INT(length);
	if (len > ary_len) {
		len = ary_len;
	}
	
	bytes = new unsigned char[len]; 
	for (i = 0; i < len; i++) {
        bytes[i] = (unsigned char)NUM2CHR(ptr[i]); 
    } 
	
	nBytesWrite = seri->writeBytes(bytes, len);
	delete[] bytes;
	
	return INT2NUM(nBytesWrite);
}

VALUE wrap_ofSerial_writeByte(VALUE self, VALUE singleByte)   
{    
	ofSerial *seri;
	Data_Get_Struct(self, ofSerial, seri);
	return seri->writeByte((unsigned char)NUM2CHR(singleByte)) ? Qtrue : Qfalse;
}

VALUE wrap_ofSerial_readByte(VALUE self)   
{    
	ofSerial *seri;
	Data_Get_Struct(self, ofSerial, seri);
	return INT2FIX(seri->readByte());
}

VALUE wrap_ofSerial_bVerbose(VALUE self)
{
	ofSerial *seri;
	Data_Get_Struct(self, ofSerial, seri);
	return seri->bVerbose ? Qtrue : Qfalse;
}

VALUE wrap_ofSerial_setVerbose(VALUE self, VALUE bLoudmouth)   
{    
	ofSerial *seri;
	Data_Get_Struct(self, ofSerial, seri);
	
	seri->setVerbose(RTEST(bLoudmouth));
	
	return Qnil;  
}

//---------------------------------------------------- ofMath
VALUE wrap_ofNextPow2(VALUE self, VALUE a)   
{    
	return INT2NUM(ofNextPow2(NUM2INT(a)));  
}

VALUE wrap_ofSeedRandom(int argc, VALUE *argv, VALUE self)   
{    
	VALUE val;
	if (rb_scan_args(argc, argv, "01", &val) == 0) {
		ofSeedRandom();
	}
	else {
		ofSeedRandom(NUM2INT(val));
	}
	return Qnil;  
}

VALUE wrap_ofRandom(VALUE self, VALUE val0, VALUE val1)   
{    
	return rb_float_new(ofRandom(NUM2DBL(val0), NUM2DBL(val1)));  
}

VALUE wrap_ofRandomf(VALUE self)   
{     
	return rb_float_new(ofRandomf());  
}   

VALUE wrap_ofRandomuf(VALUE self)   
{     
	return rb_float_new(ofRandomuf());  
}              

//---------------------------------------------------- OpenGL
VALUE wrap_glPushMatrix(VALUE self)   
{    
	glPushMatrix();
	return Qnil;  
}

VALUE wrap_glPopMatrix(VALUE self)   
{    
	glPopMatrix();
	return Qnil;  
}

VALUE wrap_glTranslatef(VALUE self, VALUE x, VALUE y, VALUE z)   
{    
	glTranslatef(NUM2DBL(x), NUM2DBL(y), NUM2DBL(z));
	return Qnil;  
}

VALUE wrap_glRotatef(VALUE self, VALUE angle, VALUE x, VALUE y, VALUE z)   
{    
	glRotatef(NUM2DBL(angle), NUM2DBL(x), NUM2DBL(y), NUM2DBL(z));
	return Qnil;  
}

VALUE wrap_glScalef(VALUE self, VALUE x, VALUE y, VALUE z)   
{    
	glScalef(NUM2DBL(x), NUM2DBL(y), NUM2DBL(z));
	return Qnil;  
}

//----------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif 
void Init_librbof(void)
{                
	VALUE cSimpleApp;
	VALUE cBgColorProxy;
	VALUE oBgColorInitArgs[1];
	float bright = 200.0f / 255.0f;
	oBgColorInitArgs[0] = rb_ary_new3(
		4,
		rb_float_new(bright),
		rb_float_new(bright),
		rb_float_new(bright),
		rb_float_new(1.0));
	VALUE cImage;
	VALUE cTexture;
	VALUE cTrueTypeFont;
	VALUE cSoundPlayer;
	VALUE cVideoPlayer;
	VALUE cVideoGrabber;
	VALUE cSerial;
	VALUE id_private_class_method = rb_intern("private_class_method");
	
	mod = rb_define_module("OF");
	
	rb_define_const(mod, "WINDOW", INT2FIX(OF_WINDOW));
	rb_define_const(mod, "FULLSCREEN", INT2FIX(OF_FULLSCREEN));
	rb_define_const(mod, "GAME_MODE", INT2FIX(OF_GAME_MODE));
	rb_define_const(mod, "RECTMODE_CORNER", INT2FIX(OF_RECTMODE_CORNER));
	rb_define_const(mod, "RECTMODE_CENTER", INT2FIX(OF_RECTMODE_CENTER));
	rb_define_const(mod, "IMAGE_GRAYSCALE", INT2FIX(OF_IMAGE_GRAYSCALE));
	rb_define_const(mod, "IMAGE_COLOR", INT2FIX(OF_IMAGE_COLOR));
	rb_define_const(mod, "IMAGE_COLOR_ALPHA", INT2FIX(OF_IMAGE_COLOR_ALPHA));
	rb_define_const(mod, "IMAGE_UNDEFINED", INT2FIX(OF_IMAGE_UNDEFINED));
	rb_define_const(mod, "POLY_WINDING_ODD", INT2FIX(OF_POLY_WINDING_ODD));
	rb_define_const(mod, "POLY_WINDING_NONZERO", INT2FIX(OF_POLY_WINDING_NONZERO));
	rb_define_const(mod, "POLY_WINDING_POSITIVE", INT2FIX(OF_POLY_WINDING_POSITIVE));
	rb_define_const(mod, "POLY_WINDING_NEGATIVE", INT2FIX(OF_POLY_WINDING_NEGATIVE));
	rb_define_const(mod, "POLY_WINDING_ABS_GEQ_TWO", INT2FIX(OF_POLY_WINDING_ABS_GEQ_TWO));
	rb_define_const(mod, "CLOSE", Qtrue);
	rb_define_const(mod, "KEY_MODIFIER", INT2FIX(OF_KEY_MODIFIER));
	rb_define_const(mod, "KEY_RETURN", INT2FIX(OF_KEY_RETURN));
	rb_define_const(mod, "KEY_BACKSPACE", INT2FIX(OF_KEY_BACKSPACE));
	rb_define_const(mod, "KEY_DEL", INT2FIX(OF_KEY_DEL));
	rb_define_const(mod, "KEY_F1", INT2FIX(OF_KEY_F1));
	rb_define_const(mod, "KEY_F2", INT2FIX(OF_KEY_F2));
	rb_define_const(mod, "KEY_F3", INT2FIX(OF_KEY_F3));
	rb_define_const(mod, "KEY_F4", INT2FIX(OF_KEY_F4));
	rb_define_const(mod, "KEY_F5", INT2FIX(OF_KEY_F5));
	rb_define_const(mod, "KEY_F6", INT2FIX(OF_KEY_F6));
	rb_define_const(mod, "KEY_F7", INT2FIX(OF_KEY_F7));
	rb_define_const(mod, "KEY_F8", INT2FIX(OF_KEY_F8));
	rb_define_const(mod, "KEY_F9", INT2FIX(OF_KEY_F9));
	rb_define_const(mod, "KEY_F10", INT2FIX(OF_KEY_F10));
	rb_define_const(mod, "KEY_F11", INT2FIX(OF_KEY_F11));
	rb_define_const(mod, "KEY_F12", INT2FIX(OF_KEY_F12));
	rb_define_const(mod, "KEY_LEFT", INT2FIX(OF_KEY_LEFT));
	rb_define_const(mod, "KEY_UP", INT2FIX(OF_KEY_UP));
	rb_define_const(mod, "KEY_RIGHT", INT2FIX(OF_KEY_RIGHT));
	rb_define_const(mod, "KEY_DOWN", INT2FIX(OF_KEY_DOWN));
	rb_define_const(mod, "KEY_PAGE_UP", INT2FIX(OF_KEY_PAGE_UP));
	rb_define_const(mod, "KEY_PAGE_DOWN", INT2FIX(OF_KEY_PAGE_DOWN));
	rb_define_const(mod, "KEY_HOME", INT2FIX(OF_KEY_HOME));
	rb_define_const(mod, "KEY_END", INT2FIX(OF_KEY_END));
	rb_define_const(mod, "KEY_INSERT", INT2FIX(OF_KEY_INSERT));
	rb_define_const(mod, "GL_COLOR_INDEX", INT2FIX(GL_COLOR_INDEX));
	rb_define_const(mod, "GL_STENCIL_INDEX", INT2FIX(GL_STENCIL_INDEX));
	rb_define_const(mod, "GL_DEPTH_COMPONENT", INT2FIX(GL_DEPTH_COMPONENT));
	rb_define_const(mod, "GL_RED", INT2FIX(GL_RED));
	rb_define_const(mod, "GL_GREEN", INT2FIX(GL_GREEN));
	rb_define_const(mod, "GL_BLUE", INT2FIX(GL_BLUE));
	rb_define_const(mod, "GL_ALPHA", INT2FIX(GL_ALPHA));
	rb_define_const(mod, "GL_RGB", INT2FIX(GL_RGB));
	rb_define_const(mod, "GL_RGBA", INT2FIX(GL_RGBA));
	rb_define_const(mod, "GL_LUMINANCE", INT2FIX(GL_LUMINANCE));
	rb_define_const(mod, "GL_LUMINANCE_ALPHA", INT2FIX(GL_LUMINANCE_ALPHA));
	rb_define_const(mod, "LOOP_NONE", INT2FIX(OF_LOOP_NONE));
	rb_define_const(mod, "LOOP_PALINDROME", INT2FIX(OF_LOOP_PALINDROME));
	rb_define_const(mod, "LOOP_NORMAL", INT2FIX(OF_LOOP_NORMAL));
	rb_define_const(mod, "PI", rb_float_new(PI));
	rb_define_const(mod, "TWO_PI", rb_float_new(TWO_PI));
	rb_define_const(mod, "M_TWO_PI", rb_float_new(M_TWO_PI));
	rb_define_const(mod, "FOUR_PI", rb_float_new(FOUR_PI));
	rb_define_const(mod, "HALF_PI", rb_float_new(HALF_PI));
	
	cSimpleApp = rb_define_class_under(mod, "SimpleApp", rb_cObject);
	rb_define_alloc_func(cSimpleApp, ofSimpleApp_alloc);
	rb_define_method(cSimpleApp, "setup", (RubyType *)wrap_ofSimpleApp_setup, 0);
	rb_define_method(cSimpleApp, "update", (RubyType *)wrap_ofSimpleApp_update, 0);
	rb_define_method(cSimpleApp, "draw", (RubyType *)wrap_ofSimpleApp_draw, 0);
	rb_define_method(cSimpleApp, "exit", (RubyType *)wrap_ofSimpleApp_exit, 0);
	rb_define_method(cSimpleApp, "keyPressed", (RubyType *)wrap_ofSimpleApp_keyPressed, 1);
	rb_define_method(cSimpleApp, "keyReleased", (RubyType *)wrap_ofSimpleApp_keyReleased, 1);
	rb_define_method(cSimpleApp, "mouseMoved", (RubyType *)wrap_ofSimpleApp_mouseMoved, 2);
	rb_define_method(cSimpleApp, "mouseDragged", (RubyType *)wrap_ofSimpleApp_mouseDragged, 3);
	rb_define_method(cSimpleApp, "mousePressed", (RubyType *)wrap_ofSimpleApp_mousePressed, 3);
	rb_define_method(cSimpleApp, "mouseReleased", (RubyType *)wrap_ofSimpleApp_mouseReleased, 0);
	rb_define_method(cSimpleApp, "audioReceived", (RubyType *)wrap_ofSimpleApp_audioReceived, 3);
	rb_define_method(cSimpleApp, "audioRequested", (RubyType *)wrap_ofSimpleApp_audioRequested, 3);
	rb_define_method(cSimpleApp, "mouseX", (RubyType *)wrap_ofSimpleApp_mouseX, 0);
	rb_define_method(cSimpleApp, "mouseY", (RubyType *)wrap_ofSimpleApp_mouseY, 0);
	
	rb_define_module_function(mod, "setupOpenGL", (RubyType *)wrap_ofSetupOpenGL, 3);
	rb_define_module_function(mod, "runApp", (RubyType *)wrap_ofRunApp, 1);
	rb_define_module_function(mod, "getFrameRate", (RubyType *)wrap_ofGetFrameRate, 0);
	rb_define_module_function(mod, "setFrameRate", (RubyType *)wrap_ofSetFrameRate, 1);
	rb_define_module_function(mod, "sleepMillis", (RubyType *)wrap_ofSleepMillis, 1);
	rb_define_module_function(mod, "showCursor", (RubyType *)wrap_ofShowCursor, 0);
	rb_define_module_function(mod, "hideCursor", (RubyType *)wrap_ofHideCursor, 0);
	rb_define_module_function(mod, "getWindowPositionX", (RubyType *)wrap_ofGetWindowPositionX, 0);
	rb_define_module_function(mod, "getWindowPositionY", (RubyType *)wrap_ofGetWindowPositionY, 0);
	rb_define_module_function(mod, "getScreenWidth", (RubyType *)wrap_ofGetScreenWidth, 0);
	rb_define_module_function(mod, "getScreenHeight", (RubyType *)wrap_ofGetScreenHeight, 0);
	rb_define_module_function(mod, "getWindowMode", (RubyType *)wrap_ofGetWindowMode, 0);
	rb_define_module_function(mod, "getWidth", (RubyType *)wrap_ofGetWidth, 0);
	rb_define_module_function(mod, "getHeight", (RubyType *)wrap_ofGetHeight, 0);
	rb_define_module_function(mod, "setWindowPosition", (RubyType *)wrap_ofSetWindowPosition, 2);
	rb_define_module_function(mod, "setWindowShape", (RubyType *)wrap_ofSetWindowShape, 2);
	rb_define_module_function(mod, "setWindowTitle", (RubyType *)wrap_ofSetWindowTitle, 1);
	rb_define_module_function(mod, "setFullscreen", (RubyType *)wrap_ofSetFullscreen, 1);
	rb_define_module_function(mod, "toggleFullscreen", (RubyType *)wrap_ofToggleFullscreen, 0);
	rb_define_module_function(mod, "setVerticalSync", (RubyType *)wrap_ofSetVerticalSync, 1);
	
	rb_define_module_function(mod, "getElapsedTimef", (RubyType *)wrap_ofGetElapsedTimef, 0);
	rb_define_module_function(mod, "getElapsedTimeMillis", (RubyType *)wrap_ofGetElapsedTimeMillis, 0);
	rb_define_module_function(mod, "getFrameNum", (RubyType *)wrap_ofGetFrameNum, 0);
	rb_define_module_function(mod, "getSeconds", (RubyType *)wrap_ofGetSeconds, 0);
	rb_define_module_function(mod, "getMinutes", (RubyType *)wrap_ofGetMinutes, 0);
	rb_define_module_function(mod, "getHours", (RubyType *)wrap_ofGetHours, 0);
	rb_define_module_function(mod, "getYear", (RubyType *)wrap_ofGetYear, 0);
	rb_define_module_function(mod, "getMonth", (RubyType *)wrap_ofGetMonth, 0);
	rb_define_module_function(mod, "getDay", (RubyType *)wrap_ofGetDay, 0);
	rb_define_module_function(mod, "getWeekDay", (RubyType *)wrap_ofGetWeekDay, 0);
	rb_define_module_function(mod, "launchBrowser", (RubyType *)wrap_ofLaunchBrowser, 1);
	rb_define_module_function(mod, "toDataPath", (RubyType *)wrap_ofToDataPath, 1);
	rb_define_module_function(mod, "toString", (RubyType *)wrap_ofToString, -1);
	rb_define_module_function(mod, "getVersionInfo", (RubyType *)wrap_ofGetVersionInfo, 0);
	
	cBgColorProxy = rb_define_class_under(mod, "BgColorProxy", rb_cArray);
	rb_define_method(cBgColorProxy, rb_id2name(id_aset), (RubyType *)bgColorProxy_aset, -1);
	rb_cvar_set(mod, id_bgColor, rb_class_new_instance(1, oBgColorInitArgs, cBgColorProxy), Qfalse); 
	
	rb_define_module_function(mod, "background", (RubyType *)wrap_ofBackground, 3);
	rb_define_module_function(mod, "bgColor", (RubyType *)wrap_ofBgColorPtr, 0);
	rb_define_module_function(mod, "setBackgroundAuto", (RubyType *)wrap_ofSetBackgroundAuto, 1);
	rb_define_module_function(mod, "setRectMode", (RubyType *)wrap_ofSetRectMode, 1);
	rb_define_module_function(mod, "bClearBg", (RubyType *)wrap_ofbClearBg, 0);
	rb_define_module_function(mod, "getRectMode", (RubyType *)wrap_ofGetRectMode, 0);
	rb_define_module_function(mod, "triangle", (RubyType *)wrap_ofTriangle, 6);
	rb_define_module_function(mod, "circle", (RubyType *)wrap_ofCircle, 3);
	rb_define_module_function(mod, "ellipse", (RubyType *)wrap_ofEllipse, 4);
	rb_define_module_function(mod, "line", (RubyType *)wrap_ofLine, 4);
	rb_define_module_function(mod, "rect", (RubyType *)wrap_ofRect, 4);
	rb_define_module_function(mod, "setCircleResolution", (RubyType *)wrap_ofSetCircleResolution, 1);
	rb_define_module_function(mod, "curve", (RubyType *)wrap_ofCurve, 8);
	rb_define_module_function(mod, "bezier", (RubyType *)wrap_ofBezier, 8);
	rb_define_module_function(mod, "noFill", (RubyType *)wrap_ofNoFill, 0);
	rb_define_module_function(mod, "fill", (RubyType *)wrap_ofFill, 0);
	rb_define_module_function(mod, "setColor", (RubyType *)wrap_ofSetColor, -1);
	rb_define_module_function(mod, "enableAlphaBlending", (RubyType *)wrap_ofEnableAlphaBlending, 0);
	rb_define_module_function(mod, "disableAlphaBlending", (RubyType *)wrap_ofDisableAlphaBlending, 0);
	rb_define_module_function(mod, "enableSmoothing", (RubyType *)wrap_ofEnableSmoothing, 0);
	rb_define_module_function(mod, "disableSmoothing", (RubyType *)wrap_ofDisableSmoothing, 0);
	rb_define_module_function(mod, "drawBitmapString", (RubyType *)wrap_ofDrawBitmapString, 3);
	rb_define_module_function(mod, "setupScreen", (RubyType *)wrap_ofSetupScreen, 0);
	rb_define_module_function(mod, "curveVertex", (RubyType *)wrap_ofCurveVertex, 2);
	rb_define_module_function(mod, "bezierVertex", (RubyType *)wrap_ofBezierVertex, 6);
	rb_define_module_function(mod, "setPolyMode", (RubyType *)wrap_ofSetPolyMode, 1);
	rb_define_module_function(mod, "beginShape", (RubyType *)wrap_ofBeginShape, 0);
	rb_define_module_function(mod, "vertex", (RubyType *)wrap_ofVertex, 2);
	rb_define_module_function(mod, "endShape", (RubyType *)wrap_ofEndShape, -1);
	rb_define_module_function(mod, "nextContour", (RubyType *)wrap_ofNextContour, -1);
	
	eUninitializedError = rb_define_class_under(mod, "UninitializedError", rb_eStandardError);
	cImage = rb_define_class_under(mod, "Image", rb_cObject);
	rb_define_alloc_func(cImage, ofImage_alloc);
	rb_define_method(cImage, "initialize_copy", (RubyType *)ofImage_init_copy, 1);
	rb_define_method(cImage, "loadImage", (RubyType *)wrap_ofImage_loadImage, 1);
	rb_define_method(cImage, "saveImage", (RubyType *)wrap_ofImage_saveImage, 1);
	rb_define_method(cImage, "allocate", (RubyType *)wrap_ofImage_allocate, 3);
	rb_define_method(cImage, "clear", (RubyType *)wrap_ofImage_clear, 0);
	rb_define_method(cImage, "getPixels", (RubyType *)wrap_ofImage_getPixels, 0);
	rb_define_method(cImage, "setFromPixels", (RubyType *)wrap_ofImage_setFromPixels, -1);
	rb_define_method(cImage, "setImageType", (RubyType *)wrap_ofImage_setImageType, 1);
	rb_define_method(cImage, "resize", (RubyType *)wrap_ofImage_resize, 2);
	rb_define_method(cImage, "grabScreen", (RubyType *)wrap_ofImage_grabScreen, 4);
	rb_define_method(cImage, "type", (RubyType *)wrap_ofImage_type, 0);
	rb_define_method(cImage, "width", (RubyType *)wrap_ofImage_width, 0);
	rb_define_method(cImage, "height", (RubyType *)wrap_ofImage_height, 0);
	rb_define_method(cImage, "bpp", (RubyType *)wrap_ofImage_bpp, 0);
	rb_define_method(cImage, "setUseTexture", (RubyType *)wrap_ofImage_setUseTexture, 1);
	rb_define_method(cImage, "draw", (RubyType *)wrap_ofImage_draw, -1);
	
	cTexture = rb_define_class_under(mod, "Texture", rb_cObject);
	rb_define_alloc_func(cTexture, ofTexture_alloc);
	rb_define_method(cTexture, "allocate", (RubyType *)wrap_ofTexture_allocate, 3);
	rb_define_method(cTexture, "clear", (RubyType *)wrap_ofTexture_clear, 0);
	rb_define_method(cTexture, "loadData", (RubyType *)wrap_ofTexture_loadData, 4);
	rb_define_method(cTexture, "loadScreenData", (RubyType *)wrap_ofTexture_loadScreenData, 4);
	rb_define_method(cTexture, "draw", (RubyType *)wrap_ofTexture_draw, -1);
	
	rb_cRectangle = rb_define_class_under(mod, "Rectangle", rb_cObject);
	rb_define_alloc_func(rb_cRectangle, ofRectangle_alloc);
	rb_define_method(rb_cRectangle, "initialize_copy", (RubyType *)ofRectangle_init_copy, 1);
	rb_define_method(rb_cRectangle, "initialize", (RubyType *)wrap_ofRectangle_initialize, -1);
	rb_define_method(rb_cRectangle, "x", (RubyType *)wrap_ofRectangle_x, 0);
	rb_define_method(rb_cRectangle, "y", (RubyType *)wrap_ofRectangle_y, 0);
	rb_define_method(rb_cRectangle, "width", (RubyType *)wrap_ofRectangle_width, 0);
	rb_define_method(rb_cRectangle, "height", (RubyType *)wrap_ofRectangle_height, 0);
	
	cTrueTypeFont = rb_define_class_under(mod, "TrueTypeFont", rb_cObject);
	rb_define_alloc_func(cTrueTypeFont, ofTrueTypeFont_alloc);
	rb_define_method(cTrueTypeFont, "loadFont", (RubyType *)wrap_ofTrueTypeFont_loadFont, -1);
	rb_define_method(cTrueTypeFont, "bLoadedOk", (RubyType *)wrap_ofTrueTypeFont_bLoadedOk, 0);
	rb_define_method(cTrueTypeFont, "bAntiAlised", (RubyType *)wrap_ofTrueTypeFont_bAntiAlised, 0);
	rb_define_method(cTrueTypeFont, "bFullCharacterSet", (RubyType *)wrap_ofTrueTypeFont_bFullCharacterSet, 0);
	rb_define_method(cTrueTypeFont, "getLineHeight", (RubyType *)wrap_ofTrueTypeFont_getLineHeight, 0);
	rb_define_method(cTrueTypeFont, "setLineHeight", (RubyType *)wrap_ofTrueTypeFont_setLineHeight, 1);
	rb_define_method(cTrueTypeFont, "stringWidth", (RubyType *)wrap_ofTrueTypeFont_stringWidth, 1);
	rb_define_method(cTrueTypeFont, "stringHeight", (RubyType *)wrap_ofTrueTypeFont_stringHeight, 1);
	rb_define_method(cTrueTypeFont, "getStringBoundingBox", (RubyType *)wrap_ofTrueTypeFont_getStringBoundingBox, 3);
	rb_define_method(cTrueTypeFont, "drawString", (RubyType *)wrap_ofTrueTypeFont_drawString, 3);
	rb_define_method(cTrueTypeFont, "nCharacters", (RubyType *)wrap_ofTrueTypeFont_nCharacters, 0);
	
	rb_define_module_function(mod, "soundStreamSetup", (RubyType *)wrap_ofSoundStreamSetup, -1);
	rb_define_module_function(mod, "soundStreamStop", (RubyType *)wrap_ofSoundStreamStop, 0);
	rb_define_module_function(mod, "soundStreamStart", (RubyType *)wrap_ofSoundStreamStart, 0);
	rb_define_module_function(mod, "soundStreamClose", (RubyType *)wrap_ofSoundStreamClose, 0);
	rb_define_module_function(mod, "soundStreamListDevices", (RubyType *)wrap_ofSoundStreamListDevices, 0);
	
	rb_define_module_function(mod, "soundInputStream", (RubyType *)wrap_soundInputStream, 0);
	rb_funcall(mod, id_private_class_method, 1, rb_str_new2("soundInputStream"));
	rb_define_module_function(mod, "soundOutputStream", (RubyType *)wrap_soundOutputStream, 0);
	rb_funcall(mod, id_private_class_method, 1, rb_str_new2("soundOutputStream"));
	rb_define_module_function(mod, "soundTickStream", (RubyType *)wrap_soundTickStream, 0);
	rb_funcall(mod, id_private_class_method, 1, rb_str_new2("soundTickStream"));
	
	rb_define_module_function(mod, "soundStopAll", (RubyType *)wrap_ofSoundStopAll, 0);
	rb_define_module_function(mod, "soundSetVolume", (RubyType *)wrap_ofSoundSetVolume, 1);
	rb_define_module_function(mod, "soundGetSpectrum", (RubyType *)wrap_ofSoundGetSpectrum, 1);
	cSoundPlayer = rb_define_class_under(mod, "SoundPlayer", rb_cObject);
	rb_define_alloc_func(cSoundPlayer, ofSoundPlayer_alloc);
	rb_define_method(cSoundPlayer, "loadSound", (RubyType *)wrap_ofSoundPlayer_loadSound, -1);
	rb_define_method(cSoundPlayer, "unloadSound", (RubyType *)wrap_ofSoundPlayer_unloadSound, 0);
	rb_define_method(cSoundPlayer, "play", (RubyType *)wrap_ofSoundPlayer_play, 0);
	rb_define_method(cSoundPlayer, "stop", (RubyType *)wrap_ofSoundPlayer_stop, 0);
	rb_define_method(cSoundPlayer, "setVolume", (RubyType *)wrap_ofSoundPlayer_setVolume, 1);
	rb_define_method(cSoundPlayer, "setPan", (RubyType *)wrap_ofSoundPlayer_setPan, 1);
	rb_define_method(cSoundPlayer, "setSpeed", (RubyType *)wrap_ofSoundPlayer_setSpeed, 1);
	rb_define_method(cSoundPlayer, "setPaused", (RubyType *)wrap_ofSoundPlayer_setPaused, 1);
	rb_define_method(cSoundPlayer, "setLoop", (RubyType *)wrap_ofSoundPlayer_setLoop, 1);
	rb_define_method(cSoundPlayer, "setMultiPlay", (RubyType *)wrap_ofSoundPlayer_setMultiPlay, 1);
	rb_define_method(cSoundPlayer, "setPosition", (RubyType *)wrap_ofSoundPlayer_setPosition, 1);
	rb_define_method(cSoundPlayer, "getPosition", (RubyType *)wrap_ofSoundPlayer_getPosition, 0);
	rb_define_method(cSoundPlayer, "getIsPlaying", (RubyType *)wrap_ofSoundPlayer_getIsPlaying, 0);
	rb_define_method(cSoundPlayer, "getSpeed", (RubyType *)wrap_ofSoundPlayer_getSpeed, 0);
	rb_define_method(cSoundPlayer, "getPan", (RubyType *)wrap_ofSoundPlayer_getPan, 0);
	
	cVideoPlayer = rb_define_class_under(mod, "VideoPlayer", rb_cObject);
	rb_define_alloc_func(cVideoPlayer, ofVideoPlayer_alloc);
	rb_define_method(cVideoPlayer, "loadMovie", (RubyType *)wrap_ofVideoPlayer_loadMovie, 1);
	rb_define_method(cVideoPlayer, "closeMovie", (RubyType *)wrap_ofVideoPlayer_closeMovie, 0);
	rb_define_method(cVideoPlayer, "idleMovie", (RubyType *)wrap_ofVideoPlayer_idleMovie, 0);
	rb_define_method(cVideoPlayer, "play", (RubyType *)wrap_ofVideoPlayer_play, 0);
	rb_define_method(cVideoPlayer, "stop", (RubyType *)wrap_ofVideoPlayer_stop, 0);
	rb_define_method(cVideoPlayer, "width", (RubyType *)wrap_ofVideoPlayer_width, 0);
	rb_define_method(cVideoPlayer, "height", (RubyType *)wrap_ofVideoPlayer_height, 0);
	rb_define_method(cVideoPlayer, "speed", (RubyType *)wrap_ofVideoPlayer_speed, 0);
	rb_define_method(cVideoPlayer, "bLoaded", (RubyType *)wrap_ofVideoPlayer_bLoaded, 0);
	rb_define_method(cVideoPlayer, "isFrameNew", (RubyType *)wrap_ofVideoPlayer_isFrameNew, 0);
	rb_define_method(cVideoPlayer, "getPixels", (RubyType *)wrap_ofVideoPlayer_getPixels, 0);
	rb_define_method(cVideoPlayer, "getPosition", (RubyType *)wrap_ofVideoPlayer_getPosition, 0);
	rb_define_method(cVideoPlayer, "getSpeed", (RubyType *)wrap_ofVideoPlayer_getSpeed, 0);
	rb_define_method(cVideoPlayer, "getDuration", (RubyType *)wrap_ofVideoPlayer_getDuration, 0);
	rb_define_method(cVideoPlayer, "setPosition", (RubyType *)wrap_ofVideoPlayer_setPosition, 1);
	rb_define_method(cVideoPlayer, "setVolume", (RubyType *)wrap_ofVideoPlayer_setVolume, 1);
	rb_define_method(cVideoPlayer, "setLoopState", (RubyType *)wrap_ofVideoPlayer_setLoopState, 1);
	rb_define_method(cVideoPlayer, "setSpeed", (RubyType *)wrap_ofVideoPlayer_setSpeed, 1);
	rb_define_method(cVideoPlayer, "setUseTexture", (RubyType *)wrap_ofVideoPlayer_setUseTexture, 1);
	rb_define_method(cVideoPlayer, "draw", (RubyType *)wrap_ofVideoPlayer_draw, -1);
	rb_define_method(cVideoPlayer, "setPaused", (RubyType *)wrap_ofVideoPlayer_setPaused, 1);
	
	cVideoGrabber = rb_define_class_under(mod, "VideoGrabber", rb_cObject);
	rb_define_alloc_func(cVideoGrabber, ofVideoGrabber_alloc);
	rb_define_method(cVideoGrabber, "listDevices", (RubyType *)wrap_ofVideoGrabber_listDevices, 0);
	rb_define_method(cVideoGrabber, "isFrameNew", (RubyType *)wrap_ofVideoGrabber_isFrameNew, 0);
	rb_define_method(cVideoGrabber, "grabFrame", (RubyType *)wrap_ofVideoGrabber_grabFrame, 0);
	rb_define_method(cVideoGrabber, "close", (RubyType *)wrap_ofVideoGrabber_close, 0);
	rb_define_method(cVideoGrabber, "initGrabber", (RubyType *)wrap_ofVideoGrabber_initGrabber, 2);
	rb_define_method(cVideoGrabber, "videoSettings", (RubyType *)wrap_ofVideoGrabber_videoSettings, 0);
	rb_define_method(cVideoGrabber, "getPixels", (RubyType *)wrap_ofVideoGrabber_getPixels, 0);
	rb_define_method(cVideoGrabber, "setVerbose", (RubyType *)wrap_ofVideoGrabber_setVerbose, 1);
	rb_define_method(cVideoGrabber, "setDeviceID", (RubyType *)wrap_ofVideoGrabber_setDeviceID, 1);
	rb_define_method(cVideoGrabber, "setUseTexture", (RubyType *)wrap_ofVideoGrabber_setUseTexture, 1);
	rb_define_method(cVideoGrabber, "draw", (RubyType *)wrap_ofVideoGrabber_draw, -1);
	rb_define_method(cVideoGrabber, "width", (RubyType *)wrap_ofVideoGrabber_width, 0);
	rb_define_method(cVideoGrabber, "height", (RubyType *)wrap_ofVideoGrabber_height, 0);
	
	cSerial = rb_define_class_under(mod, "Serial", rb_cObject);
	rb_define_alloc_func(cSerial, ofSerial_alloc);
	rb_define_method(cSerial, "enumerateDevices", (RubyType *)wrap_ofSerial_enumerateDevices, 0);
	rb_define_method(cSerial, "close", (RubyType *)wrap_ofSerial_close, 0);
	rb_define_method(cSerial, "setup", (RubyType *)wrap_ofSerial_setup, -1);
	rb_define_method(cSerial, "readBytes", (RubyType *)wrap_ofSerial_readBytes, 2);
	rb_define_method(cSerial, "writeBytes", (RubyType *)wrap_ofSerial_writeBytes, 2);
	rb_define_method(cSerial, "writeByte", (RubyType *)wrap_ofSerial_writeByte, 1);
	rb_define_method(cSerial, "readByte", (RubyType *)wrap_ofSerial_readByte, 0);
	rb_define_method(cSerial, "bVerbose", (RubyType *)wrap_ofSerial_bVerbose, 0);
	rb_define_method(cSerial, "setVerbose", (RubyType *)wrap_ofSerial_setVerbose, 1);
		
	rb_define_module_function(mod, "nextPow2", (RubyType *)wrap_ofNextPow2, 1);
	rb_define_module_function(mod, "seedRandom", (RubyType *)wrap_ofSeedRandom, -1);
	rb_define_module_function(mod, "random", (RubyType *)wrap_ofRandom, 2);
	rb_define_module_function(mod, "randomf", (RubyType *)wrap_ofRandomf, 0);
	rb_define_module_function(mod, "randomuf", (RubyType *)wrap_ofRandomuf, 0);
	
	rb_define_module_function(mod, "pushMatrix", (RubyType *)wrap_glPushMatrix, 0);
	rb_define_module_function(mod, "popMatrix", (RubyType *)wrap_glPopMatrix, 0);
	rb_define_module_function(mod, "translate", (RubyType *)wrap_glTranslatef, 3);
	rb_define_module_function(mod, "rotate", (RubyType *)wrap_glRotatef, 4);
	rb_define_module_function(mod, "scale", (RubyType *)wrap_glScalef, 3);
}   
#ifdef __cplusplus
}
#endif  